/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"

#include <线性代数/矢量计算.h>
#include <core/结构数据.h>
#include <matXX.h>

#include "core/shader_built_in_functions.h"
#include "数学/数学.h"


vec4 f_math_quat两向量(const vec3& dirA, const vec3& dirB) {
	float32 弧度AB = f_graph_两向量夹角弧度180(dirA, dirB);
	return f_graph_从轴向角度计算四元数(vec_normalize2(vec_cross(dirA, dirB)), 弧度AB);
}



void f_math_quat两向量m(const S_Vec3Array* dirA, const S_Vec3Array* dirB, S_Vec4Array* r) {
	uint32 num = DEF_Max(dirA->count, dirB->count);

	f_core_array_resize((S_Array*)r, num);

	bool s0单例 = dirA->count < num;
	bool s1单例 = dirB->count < num;


//#pragma omp parallel for
	for (int32 i = 0; i < num; ++i) {
		
		r->ptr_userData[i] = f_math_quat两向量(
								s0单例 ? dirA->ptr_userData[0] : dirA->ptr_userData[i], 
								s1单例 ? dirB->ptr_userData[0] : dirB->ptr_userData[i]);
	}
}

void f_math_quat以轴向和角度构建m(S_Vec4Array* quat, const S_Vec3Array* v, const S_F32Array* a) {
	uint32 num = DEF_Max(v->count, a->count);

	bool in1单例 = v->count < num;
	bool in2单例 = a->count < num;

	f_core_array_resize((S_Array*)quat, num);

	if (num > 8192) {
#pragma omp parallel for num_threads(DEF_Min(16, num))
		for (int32 i = 0; i < num; ++i) {
			vec3 vp;
			if (in1单例) vp = v->ptr_userData[0];
			else vp = v->ptr_userData[i];

			float32 ap;
			if (in2单例) ap = a->ptr_userData[0];
			else ap = a->ptr_userData[i];

			quat->ptr_userData[i] = f_graph_从轴向角度计算四元数(vp, ap);
		}
	}
	else {
		for (int32 i = 0; i < num; ++i) {
			vec3 vp;
			if (in1单例) vp = v->ptr_userData[0];
			else vp = v->ptr_userData[i];

			float32 ap;
			if (in2单例) ap = a->ptr_userData[0];
			else ap = a->ptr_userData[i];

			quat->ptr_userData[i] = f_graph_从轴向角度计算四元数(vp, ap);
		}
	}
}


void f_math_quat相乘m(const S_Vec4Array* dirA, const S_Vec4Array* dirB, S_Vec4Array* r) {
	uint32 num = DEF_Max(dirA->count, dirB->count);
	f_core_array_resize((S_Array*)r, num);

	bool s0单例 = dirA->count < num;
	bool s1单例 = dirB->count < num;

	bool 是否单值 = dirB->count >= num;

	if (num > 8192) {
#pragma omp parallel for num_threads(DEF_Min(16, num))
		for (int32 i = 0; i < num; ++i) {
			r->ptr_userData[i] = f_graph_quat相乘(
				s0单例 ? dirA->ptr_userData[0] : dirA->ptr_userData[i],
				s1单例 ? dirB->ptr_userData[0] : dirB->ptr_userData[i]);
		}
	}
	else {
		for (uint32 i = 0; i < num; ++i) {
			r->ptr_userData[i] = f_graph_quat相乘(
				s0单例 ? dirA->ptr_userData[0] : dirA->ptr_userData[i],
				s1单例 ? dirB->ptr_userData[0] : dirB->ptr_userData[i]);
		}
	}
}

void f_math_quat变换m(const S_Vec3Array* dirA, const S_Vec4Array* dirB, S_Vec3Array* r, int32 方式) {
	uint32 num = DEF_Max(dirA->count, dirB->count);

	f_core_array_resize((S_Array*)r, num);

	bool 是否单值1 = dirA->count < num;
	bool 是否单值2 = dirB->count < num;

	if (num > 8192) {
		switch (方式) {
			case 0: {
#pragma omp parallel for num_threads(DEF_Min(16, num))
				for (int32 i = 0; i < num; ++i) {
					r->ptr_userData[i] = f_graph_quatTranform(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i]);
				}
				break;
			}
			case 1: {
#pragma omp parallel for num_threads(DEF_Min(16, num))
				for (int32 i = 0; i < num; ++i) {
					r->ptr_userData[i] = f_graph_quatTranformInv(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i]);
				}
				break;
			}
			case 2: {
				vec3 上一个坐标{};
				for (int32 i = 0; i < num; ++i) {
					vec3 v = 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i];
					r->ptr_userData[i] = f_graph_quatTranform(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], v - 上一个坐标) + 上一个坐标;
					上一个坐标 = v;
				}
				break;
			}
			case 3: {
				vec3 上一个坐标{};
				for (int32 i = 0; i < num; ++i) {
					vec3 v = 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i];
					r->ptr_userData[i] = f_graph_quatTranformInv(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], v - 上一个坐标) + 上一个坐标;
					上一个坐标 = v;
				}
				break;
			}
		}
	}
	else {
		switch (方式) {
			case 0: {
				for (int32 i = 0; i < num; ++i) {
					r->ptr_userData[i] = f_graph_quatTranform(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i]);
				}
				break;
			}
			case 1: {
				for (int32 i = 0; i < num; ++i) {
					r->ptr_userData[i] = f_graph_quatTranformInv(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i]);
				}
				break;
			}
			case 2: {
				vec3 上一个坐标{};
				for (int32 i = 0; i < num; ++i) {
					vec3 v = 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i];
					r->ptr_userData[i] = f_graph_quatTranform(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], v - 上一个坐标) + 上一个坐标;
					上一个坐标 = v;
				}
				break;
			}
			case 3: {
				vec3 上一个坐标{};
				for (int32 i = 0; i < num; ++i) {
					vec3 v = 是否单值1 ? dirA->ptr_userData[0] : dirA->ptr_userData[i];
					r->ptr_userData[i] = f_graph_quatTranformInv(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], v - 上一个坐标) + 上一个坐标;

					//vec3 v1 = v - 上一个坐标;
					//float32 l = length(v1);
					//v1 = normalize(f_graph_quatTranformInv(是否单值2 ? dirB->ptr_userData[0] : dirB->ptr_userData[i], v1));
					//r->ptr_userData[i] = 上一个坐标 + v1 * l;

					上一个坐标 = v;
				}
				break;
			}
		}
	}
}


void f_math_四元数转欧拉角m(const S_Vec4Array* quat, S_Vec3Array* r) {
	uint32 num = quat->count;
	f_core_array_resize((S_Array*)r, num);
	
	for (uint32 i = 0; i < num; ++i) {
		r->ptr_userData[i] = f_graph_四元数转欧拉角(quat->ptr_userData[i]);
	}
}
void f_math_四元数转3X3矩阵m(const S_Vec4Array* quat, S_Mat33Array* r) {
	uint32 num = quat->count;
	f_core_array_resize((S_Array*)r, num);

	for (uint32 i = 0; i < num; ++i) {
		r->ptr_userData[i] = f_mat3x3_quat(quat->ptr_userData[i]);
	}
}
void f_math_四元数转4X4矩阵m(const S_Vec4Array* quat, S_Mat44Array* r) {
	uint32 num = quat->count;
	f_core_array_resize((S_Array*)r, num);

	for (uint32 i = 0; i < num; ++i) {
		r->ptr_userData[i] = f_mat4x4_quat(quat->ptr_userData[i]);
	}
}


vec3 f_math_轴向旋转变换(vec3 point, vec3 轴向, float32 角度, int32 方式) {
	switch (方式) {
	case 1: {
		轴向 = vec_cross(point, 轴向);
		break;
	}
	}
	vec4 quat = f_graph_从轴向角度计算四元数(轴向, 角度);
	point = f_graph_quatTranform(quat, point);
	return point;
}

void f_math_轴向旋转变换m(S_Vec3Array* 新坐标, const S_Vec3Array* point, const S_Vec3Array* 轴向, S_F32Array* 弧度, int32 方式) {
	uint32 num = DEF_Max(point->count, 轴向->count);
	num = DEF_Max(弧度->count, num);

	bool in1单例 = point->count < num;
	bool in2单例 = 轴向->count < num;
	bool in3单例 = 弧度->count < num;

	f_core_array_resize((S_Array*)新坐标, num);
	

	switch (方式) {
	//累加
	case 1: {
		vec4 last_quat = {0,0,0,1};
		vec3 上一个点坐标 = {};
		vec3 上一个变换后坐标 = {};
		for (uint32 i = 0; i < num; ++i) {
			vec3 p;
			if(in1单例) p = point->ptr_userData[0];
			else p = point->ptr_userData[i];

			vec3 v;
			if(in2单例) v = 轴向->ptr_userData[0];
			else v = 轴向->ptr_userData[i];

			float32 a;
			if(in3单例) a = 弧度->ptr_userData[0];
			else a = 弧度->ptr_userData[i];

			vec4 quat = f_graph_quat相乘(f_graph_quatNormalize(f_graph_从轴向角度计算四元数(v, a)), last_quat);
			新坐标->ptr_userData[i] = f_graph_quatTranform(quat, p - 上一个点坐标) + 上一个变换后坐标;
			last_quat = quat;
			上一个点坐标 = p;
			上一个变换后坐标 = 新坐标->ptr_userData[i];
		}
		break;
	}
	default: {
		
		for (uint32 i = 0; i < num; ++i) {
			vec3 p;
			if(in1单例) p = point->ptr_userData[0];
			else p = point->ptr_userData[i];

			vec3 v;
			if(in2单例) v = 轴向->ptr_userData[0];
			else v = 轴向->ptr_userData[i];

			float32 a;
			if(in3单例) a = 弧度->ptr_userData[0];
			else a = 弧度->ptr_userData[i];

			vec4 quat = f_graph_从轴向角度计算四元数(v, a);
			新坐标->ptr_userData[i] = f_graph_quatTranform(quat, p);
		}
		break;
	}
	}
}





vec3 f_math_绕点旋转(const vec3& point, const vec3& 轴向, const float32 弧度, const vec3& 中心) {
	vec4 quat = f_graph_从轴向角度计算四元数(轴向, 弧度);
	return f_graph_quatTranform(quat, (point - 中心)) + 中心;
}

void f_math_绕点旋转m(S_Vec3Array* r, const S_Vec3Array* point, const S_Vec3Array* 轴向, const S_F32Array* 弧度, const vec3& 中心) {
	uint32 num = DEF_Max(point->count, 轴向->count);
	num = DEF_Max(弧度->count, num);

	bool in1单例 = point->count < num;
	bool in2单例 = 轴向->count < num;
	bool in3单例 = 弧度->count < num;

	f_core_array_resize((S_Array*)r, num);

	vec4 last_quat = {0,0,0,1};
	for (uint32 i = 0; i < num; ++i) {
		vec3 p;
		if(in1单例) p = point->ptr_userData[0];
		else p = point->ptr_userData[i];

		vec3 a;
		if(in2单例) a = 轴向->ptr_userData[0];
		else a = 轴向->ptr_userData[i];

		float32 d;
		if(in3单例) d = 弧度->ptr_userData[0];
		else d = 弧度->ptr_userData[i];


		vec4 quat = f_graph_quat相乘(f_graph_从轴向角度计算四元数(a, d), last_quat);
		r->ptr_userData[i] = f_graph_quatTranform(quat, (p - 中心)) + 中心;
		last_quat = quat;
	}
}



